标签
spring
数据库
字数
2487 字
阅读时间
13 分钟
一、概述
SpringData Redis的作用是通过一段简单的配置即可访问redis服务,它的底层是对java提供的redis开发包(比如jedis等)进行了高度封装,主要提供了如下功能:
- 连接池自动管理,提供了一个高度封装的RedisTemplate类,基于这个类的对象可以对redis进行各种操作
- 针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
- ValueOperations:简单字符串类型数据操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:map类型的数据操作
- ListOperations:list类型的数据操作
1.1 序列化器
SpringData Redis在保存数据的时候,底层有一个序列化器在工作,它会将要保存的数据(键和值)按照一定的规则进行序列化操作后再进行存储。spring-data-redis提供如下几种序列化器:
- StringRedisSerializer: 简单的字符串序列化
- GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
- Jackson2JsonRedisSerializer: 序列化对象为json字符串
- GenericJackson2JsonRedisSerializer:功能同上,但是更容易反序列化
- OxmSerializer: 序列化对象为xml字符串
- JdkSerializationRedisSerializer: 序列化对象为二进制数据
RedisTemplate默认使用的是JdkSerializationRedisSerializer对数据进行序列化。
1.2 运行原理分析
- 通过JedisConnectionFactory连接工程获取jedis连接
- 通过JedisConnectionFactory产生JedisConnetion
SpringData提供redisTemplate就是在原生的Jedis或者其他操作redis的技术上做的一层封装,它屏蔽掉了这些原生技术的实现细节,统一了调用接口,使得我们的操作更加简单明了。
二、使用示例
2.1 入门Demo
依赖
xml
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.3</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>配置
xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置读取 properties 文件的工具类 -->
<context:property-placeholder location="classpath:redis.properties"/>
<!-- Jedis 连接池 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}"/>
<property name="maxIdle" value="${redis.pool.maxIdle}"/>
<property name="minIdle" value="${redis.pool.minIdle}"/>
</bean>
<!-- Jedis 的连接工厂 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionF actory">
<property name="hostName" value="${redis.conn.hostName}"/>
<property name="port" value="${redis.conn.port}"/>
<property name="poolConfig" ref="poolConfig"/>
</bean>
<!-- Redis 模板对象 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<!-- 序列化器:能够把我们储存的 key 与 value 做序列化处理的对象 -->
<!-- 配置默认的序列化器 -->
<!-- keySerializer、valueSerializer 配置 Redis 中的 String 类型 key 与 value 的序列化器 -->
<!-- HashKeySerializer、HashValueSerializer 配置 Redis 中的 Hash 类型 key 与 value 的序列化器 -->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
</bean>
</beans>使用demo
java
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 添加键值对
*/
public void test1(){
this.redisTemplate.opsForValue().set("key", "test");
}
/**
* 获取 redis 中的数据
*/
public void test2(){
String str = (String)this.redisTemplate.opsForValue().get("key");
System.out.println(str);
}
//Spring Data Redisd 存储实体对象
//更换序列化器 jdk序列化器
this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
this.redisTemplate.opsForValue().set("users", users);
//json格式
this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Users.class));
this.redisTemplate.opsForValue().set("usersjson", users);三、核心知识
3.1 修改使用的序列化器
通过配置文件选择
xml
<!--redisTemplate-->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<!--指定非hash类型的数据序列化器-->
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
</bean>通过RedisTemplate设定
java
@Test
public void test1() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
//存入数据
redisTemplate.opsForValue().set("name", "heima");
//查询数据
String name = (String) redisTemplate.opsForValue().get("name");
System.out.println(name);
}3.2 操作不同类型数据示例
String类型
java
package com.itheima.test;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisStringTest {
@Autowired
private RedisTemplate redisTemplate;
ValueOperations<String, String> operations = null;
@Before
public void init() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
operations = redisTemplate.opsForValue();
}
@Test
public void testSet() {
//向数据库中保存name--heima
//operations.set("name","heima");
//相关数据库保存name1--heima1 有效时间为10s
//operations.set("name1", "heima1", 10, TimeUnit.SECONDS);
//替换 heima ---> heXXa offset 索引位置是从0开始
//operations.set("name", "XX", 2);
//当key不存在的时候,执行保存操作;当key存在的时候,什么都不做
//operations.setIfAbsent("name1","heima");
//批量保存
// Map map = new HashMap();
// map.put("name2", "heima2");
// map.put("name3", "heima3");
// map.put("name4", "heima4");
//
// operations.multiSet(map);
//追加 当key存在时,会执行追加操作;当key不存在时,会执行保存操作
operations.append("name5", "Heima");
}
@Test
public void testGet() {
//根据key获取value
/* String value = operations.get("name");
System.out.println(value);//heXXaHeima*/
//首先根据key获取value,然后再根据value进行截取,从start位置截取到end位置[包含start和end]
/* String value2 = operations.get("name", 5, 7);
System.out.println(value2);//heXXaHeima-->Hei*/
//批量获取
// List<String> keys = new ArrayList<>();
// keys.add("name2");
// keys.add("name3");
// keys.add("name4");
// List<String> values = operations.multiGet(keys);
// for (String s : values) {
// System.out.println(s);
// }
//根据key获取value的长度
Long size = operations.size("name");
System.out.println(size);
}
//自增
@Test
public void testIncrement() {
operations.set("age", "18");
operations.increment("age");//自增1--->19
System.out.println(operations.get("age"));
operations.increment("age", 5);//自增5
System.out.println(operations.get("age"));//---->24
//自减
//operations.decrement("age")
}
//删除
@Test
public void testDelete() {
//单个删除
redisTemplate.delete("name");
List<String> keys = new ArrayList<>();
keys.add("name2");
keys.add("name3");
keys.add("name4");
//批量删除
redisTemplate.delete(keys);
}
}Hash类型
java
package com.itheima.test;
import com.itheima.domain.Article;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisHashTest {
@Autowired
private RedisTemplate redisTemplate;
HashOperations<String, String, Article> operations = null;
@Before
public void init() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
operations = redisTemplate.opsForHash();
}
//保存
@Test
public void testPut() {
Article article = new Article();
article.setTitle("黑马");
article.setAuthor("黑马程序员");
article.setCreateTime(new Date());
operations.put("article", "3", article);
}
//获取
@Test
public void testGet() {
//判断hashkey是否存在
Boolean flag = operations.hasKey("article", "3");
System.out.println(flag);
//根据key和hashkay获取操作
Article article = operations.get("article", "2");
System.out.println(article);
//根据key获取所有的hashkey
Set<String> set = operations.keys("article");
for (String s : set) {
System.out.println(s);
}
List<Article> articles = operations.values("article");
for (Article art : articles) {
System.out.println(art);
}
Map<String, Article> map = operations.entries("article");
for (Map.Entry<String, Article> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
//删除
@Test
public void testDelete() {
//当hash中的数据全部被删除后,整个hash就没了
operations.delete("article", "2", "3");
}
}List类型
java
package com.itheima.test;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisListTest {
@Autowired
private RedisTemplate redisTemplate;
ListOperations<String, String> operations = null;
@Before
public void init() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
operations = redisTemplate.opsForList();
}
//增加
@Test
public void testAdd() {
//从左边添加一个元素
operations.leftPush("students", "zhangsan");
//从左边添加多个元素
operations.leftPushAll("students", "lisi", "wangwu", "zhaoliu");
//从右边添加一个元素
operations.rightPush("students", "zhangsan1");
//从右边添加多个元素
operations.rightPushAll("students", "lisi", "wangwu", "zhaoliu");
}
//查询
@Test
public void testFind() {
//根据key和索引进行查询
//0和正数代表从左边开始 0 1 2
//负数代表从右边开始 -1 -2 -3
String student = operations.index("students", 1);
System.out.println(student);
String student1 = operations.index("students", -2);
System.out.println(student1);
//范围查询
//根据key [start,end] 包括首尾
List<String> students = operations.range("students", 0, 2);
for (String s : students) {
System.out.println(s);
}
}
//删除
@Test
public void testRemove(){
//从左边删除第一个元素
//String s = operations.leftPop("students");
//从右边删除第一个元素
//operations.rightPop("students");
// count > 0:删除左边起第几个等于指定值的元素
// count < 0:删除右边起第几个等于指定值的元素
// count = 0:删除所有等于value的元素。
//删除左边起第二个wangwu
operations.remove("students",2,"wangwu");
}
}Set类型
java
package com.itheima.test;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import java.util.Set;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisSetTest {
@Autowired
private RedisTemplate redisTemplate;
SetOperations<String, String> operations = null;
@Before
public void init() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
operations = redisTemplate.opsForSet();
}
//增加
@Test
public void testAdd() {
operations.add("students","zhangsan","lisi","wangwu","zhangsan");
}
//查询
@Test
public void testFind() {
//查询所有元素
/* Set<String> students = operations.members("students");
for (String student : students) {
System.out.println(student);
}*/
//随机获取一个元素
/* String student = operations.randomMember("students");
System.out.println(student);*/
//随机多个元素[可能会重复]
List<String> stus = operations.randomMembers("students", 2);
for (String stu : stus) {
System.out.println(stu);
}
}
//删除
@Test
public void testRemove() {
//移除元素,并返回移除成功个数
Long count = operations.remove("students", "zhangsan", "wangwu","sunliu");
System.out.println(count);
//随机移除指定集合中的多少个元素
List<String> students = operations.pop("students", 2);
for (String student : students) {
System.out.println(student);
}
}
//多集合操作
@Test
public void testMoreSet(){
operations.add("names1", "zhangsan", "li", "wangwu");
operations.add("names2", "zhangsan", "li", "zhaoliu");
//取交集
/* Set<String> sets1 = operations.intersect("names1", "names2");
for (String s : sets1) {
System.out.println(s);
}*/
//取并集
/* Set<String> sets2 = operations.union("names1", "names2");
for (String s : sets2) {
System.out.println(s);
}*/
//取差集[第一个集合中存在,但是在第二个集合中不存在的元素]
Set<String> sets3 = operations.difference("names2", "names1");
for (String s : sets3) {
System.out.println(s);
}
}
}ZSet类型
java
package com.itheima.test;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
import java.util.Set;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-redis.xml")
public class RedisZSetTest {
@Autowired
private RedisTemplate redisTemplate;
ZSetOperations<String, String> operations = null;
@Before
public void init() {
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
operations = redisTemplate.opsForZSet();
}
//增加
@Test
public void testAdd() {
operations.add("students", "zhangsan", 100);
operations.add("students", "lisi", 60);
operations.add("students", "wangwu", 80);
}
//分数的增减
@Test
public void testScore() {
//incrementScore 可以用来增减分数 增加就用正数 减少用负数
//增加分数
operations.incrementScore("students", "wangwu", 30);
//减少分数
operations.incrementScore("students", "wangwu", -70);
}
//查询一个元素的信息
@Test
public void testFindOne() {
//查询一个元素的分数
Double score = operations.score("students", "wangwu");
System.out.println(score);
//查询一个元素在集合中的排名 排名从0开始
Long rank = operations.rank("students", "zhangsan");
System.out.println(rank);
}
//根据一个区间获得一个列表
@Test
public void testFindList() {
//根据排名区间来获取元素列表
Set<String> students = operations.range("students", 0, 2);
for (String student : students) {
System.out.println(student);
}
System.out.println("=============");
Set<ZSetOperations.TypedTuple<String>> set = operations.rangeWithScores("students", 0, 2);
for (ZSetOperations.TypedTuple<String> tuple : set) {
System.out.println(tuple.getValue() + "同学,得了" + tuple.getScore() + "分");
}
System.out.println("---------------------------------");
//根据分数区间来获取列表
Set<String> students2 = operations.rangeByScore("students", 60, 90);
for (String student : students2) {
System.out.println(student);
}
System.out.println("=============");
Set<ZSetOperations.TypedTuple<String>> set2 = operations.rangeByScoreWithScores("students", 60, 90);
for (ZSetOperations.TypedTuple<String> tuple : set2) {
System.out.println(tuple.getValue() + "同学,得了" + tuple.getScore() + "分");
}
}
//统计
@Test
public void testCount() {
//统计一个集合中元素
Long zCard = operations.zCard("students");
System.out.println(zCard);
//根据一个分数区间统计元素数量
Long count = operations.count("students", 50, 100);
System.out.println(count);
}
//删除
@Test
public void testRemove() {
//根据key-value删除 value允许传入多个
//operations.remove("students","zhangsan","lisi");
//根据排名区间删除
//operations.removeRange("students", 0, 1);
//根据分数区间删除
operations.removeRangeByScore("students", 70, 100);
}
}